package org.thingsboard.server.controller.swagger;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.config.SpringUtils;
import org.thingsboard.server.controller.BaseController;
import org.thingsboard.server.dao.jpa.*;
import org.thingsboard.server.dao.jpa.imp.*;
import org.thingsboard.server.service.transport.ProcessService;
import org.thingsboard.server.service.transport.RuleEngineTransportService;
import org.thingsboard.server.transport.mqtt.MqttTopics;
import org.thingsboard.server.utils.AjaxResult;
import org.thingsboard.server.utils.msg.MqttReqMsg;
import org.thingsboard.server.utils.msg.MqttReqMsgBody;
import org.thingsboard.server.utils.msg.MqttReqMsgHeader;
import org.thingsboard.server.utils.msg.MsgType;

import java.sql.Date;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/iot-web/api/")
@Slf4j
public class DeviceServiceController extends BaseController{

    @Autowired
    private DevicePropertyRepository devicePropertyRepository;

    @Autowired
    private AreaRepository areaRepository;

    private static final Gson gson = new Gson();
    @Autowired
    private RuleEngineTransportService ruleEngineTransportService;

    @Autowired
    private ProcessService processService;

    @Autowired
    private TDeviceRepository tDeviceRepository;

    @Autowired
    private DeviceEventRepository deviceEventRepository;

    @Autowired
    private GatewayRepository gatewayRepository;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ConcurrentHashMap<String,Map> callbackMsgManagement;

    @Autowired
    private ConcurrentHashMap<String,String> deviceAttrManagement;

    @Autowired
    private ConcurrentHashMap<String, TApp> appManagement;

    @Autowired
    private ConcurrentHashMap<String,Object> deviceEventManagement;

    private static Map<String,TDevice> deviceMap=new HashMap();

    /**
     * 初始化数据和清缓存和内存数据
     * @throws ThingsboardException
     */
    @RequestMapping(value = "/initData", method = RequestMethod.GET)
    @ResponseBody
    public AjaxResult initData() throws ThingsboardException {
        appManagement.clear();
        deviceAttrManagement.clear();
        deviceEventManagement.clear();
        List<TGateway> lists=gatewayRepository.findGateways();
        if(!lists.isEmpty()){
            for(TGateway code:lists){
                String gatewayCode=code.getGatewayCode();
                List<TGateway> list=gatewayRepository.findAgents(gatewayCode);
                if(!list.isEmpty()){
                    for(TGateway gateway:list){
                        MqttReqMsg mqttReqMsg=new MqttReqMsg();
                        MqttReqMsgBody requestBody=new MqttReqMsgBody();
                        MqttReqMsgHeader requestHeader=new MqttReqMsgHeader();
                        requestHeader.setAgentId(gateway.getGatewayCode());
                        requestHeader.setGatewayId(gatewayCode);
                        mqttReqMsg.setRequestBody(requestBody);
                        mqttReqMsg.setRequestHead(requestHeader);
                        ruleEngineTransportService.doAgentProcess(mqttReqMsg,MqttTopics.GATEWAY_ATTRIBUTES_TOPIC);
                    }
                }
            }
            return AjaxResult.success();
        }
        return AjaxResult.error("没有网关!");
    }


    /**
     * 更新数据
     * @param request
     * @throws ThingsboardException
     */
    @RequestMapping(value = "/updateData", method = RequestMethod.POST)
    @ResponseBody
    public void updateData(@RequestBody JsonNode request) throws ThingsboardException {
        Map map=new HashMap();
        map.put("data",request);
        map.put("topic",MqttTopics.GATEWAY_ATTRIBUTES_TOPIC);
        ruleEngineTransportService.process("iot-gateway-001",null,map);
    }

    /**
     * 更新
     * @param request
     * @return
     * @throws ThingsboardException
     */
    @RequestMapping(value = "/callDeviceService", method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult updateCommond(@RequestBody Map request) throws ThingsboardException {
        Map map=new HashMap();
        Map requestBody= (Map) request.get("requestBody");
        //查询设备
        TDevice tDevice=tDeviceRepository.findByDeviceCode(requestBody.get("deviceCode")+"");
        if(null==tDevice){
            throw new ThingsboardException(ThingsboardErrorCode.ERROR_4000);
        }
        //查询网关
        TGateway gateway=gatewayRepository.findGateway(tDevice.getGatewayCode());
        Map datas=new HashMap();
        //MQTT消息头
        MqttReqMsgHeader header= new MqttReqMsgHeader(MsgType.SERVICE_CALL,gateway.getGatewayCode(),tDevice.getGatewayCode());
        datas.put("requestHead",header);
        datas.put("requestBody",requestBody);
        map.put("data",datas);
        map.put("topic",MqttTopics.GATEWAY_COMMANDS_TOPIC);
        //执行过程
        ruleEngineTransportService.process(gateway.getGatewayCode(),null,map);
        Boolean flag=false;
        int i = 30;
        while (i>0) {
            i--;
            try {
                //线程等待1秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
            if (null!=callbackMsgManagement.get(header.getMsgId())) {
                Map result=callbackMsgManagement.get(header.getMsgId());
                JsonArray args=gson.fromJson(result.get("requestBody").toString(),JsonObject.class).get("eventArg").getAsJsonArray();
                for(JsonElement arg:args){
                    if("success".equals(arg.getAsJsonObject().get("value").getAsString())){
                        flag=true;
                        break;
                    }
                }
                if(flag){
                    break;
                }
            }
        }
        callbackMsgManagement.remove(header.getMsgId());
        if(flag){
            return AjaxResult.success("操作成功");
        }
        System.out.println("调用指令超时");
        return AjaxResult.error(ThingsboardErrorCode.ERROR_5041);
    }


    @RequestMapping(value = "/getDeviceProperty", method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult getDeviceProperty(@RequestBody Map request) throws ThingsboardException {
//        deviceAttrManagement
        Map requestBody= (Map) request.get("requestBody");
        String deviceCode=requestBody.get("deviceCode")+"";
        List<String> list= (List<String>) requestBody.get("propertyList");
        List<Map> dataMap=new ArrayList<>();
        for(String map:list){
            TDeviceProperty tDeviceProperty=devicePropertyRepository.findByDpropertyCode(map);
            ArrayList strs=new ArrayList();
            String stringArg=tDeviceProperty.getDpropertyArg();
            String str="";
            if(!stringArg.isEmpty()){
                JsonArray values = gson.fromJson(stringArg, JsonObject.class).get("configArg").getAsJsonArray().get(0).getAsJsonObject().get("value").getAsJsonArray();
                strs=gson.fromJson(values, ArrayList.class);
            }
            if(strs.contains("ram")){
                str= deviceAttrManagement.get(deviceCode+map);
            }
            if(strs.contains("redis")){
                str= (String) redisTemplate.opsForValue().get(deviceCode+map);
            }
            if(null!=str&&!str.isEmpty()){
                dataMap.add(gson.fromJson(str,Map.class));
            }
        }
        Map returnMap=new HashMap();
        returnMap.put("propertyList",dataMap);
        return AjaxResult.success(returnMap);
    }

  /*  @RequestMapping(value = "/sendMap", method = RequestMethod.POST)
    public Map getMap(){
        TEvent tEvent = new TEvent();
        tEvent.setEventId(UUID.randomUUID().toString().replace("-", ""));
        tEvent.setDeviceCode("111");
        tEvent.setEventTime(new Date(System.currentTimeMillis()));
        tEvent.setEventVal("111");
        SpringUtils.getBean(TEventRepository.class).save(tEvent);
        return null;
    }*/


    /**
     * 根据地区查询设备
     * @param map
     * @return
     */
    @RequestMapping(value = "/queryDeviceList", method = RequestMethod.POST)
    public AjaxResult queryDeviceList(@RequestBody Map map){
        Map returnMap=new HashMap();
        List<String> area=null;
        if(null!=map.get("requestBody")){
            Map data= (Map) map.get("requestBody");
            if(null!=data){
                area= (List<String>) data.get("areaList");
                if(null!=area&&area.size()>0){
                    Page page = tDeviceRepository.findTDEvicePage(area,Transfer.getPageRequest(map));
                    returnMap.put("pageNo",page.getNumber());
                    returnMap.put("pageSize",page.getSize());
                    returnMap.put("pageCount",page.getTotalPages());
                    returnMap.put("data",page.getContent());
                    return AjaxResult.success(returnMap);
                }
            }
        }
        Page page = tDeviceRepository.findTDEvicePage(Transfer.getPageRequest(map));
        returnMap.put("pageNo",page.getNumber());
        returnMap.put("pageSize",page.getSize());
        returnMap.put("pageCount",page.getTotalPages());
        returnMap.put("data",page.getContent());
        return AjaxResult.success(returnMap);
    }

    /**
     * 2.3.1.2.查询设备在线状态
     * @param map
     * @return
     */
    @RequestMapping(value = "/queryDeviceStatus", method = RequestMethod.POST)
    public AjaxResult queryDeviceStatus(@RequestBody Map map){
        if(deviceMap.isEmpty()){
            List<TDevice> tDevices=  tDeviceRepository.findAll(null);
            if(!tDevices.isEmpty()){
                deviceMap= tDevices.stream().collect(Collectors.toMap(TDevice::getDeviceCode, tDevice -> tDevice));
            }
        }
        Map result=new HashMap();
        List<Map> returnMap=new ArrayList<>();
        List<String> deviceList=null;
        Map requestHead= (Map) map.get("requestHead");
        if(null!=map.get("requestBody")){
            Map data= (Map) map.get("requestBody");
            if(null!=data){
                deviceList= (List<String>) data.get("deviceList");
            }
        }
        if(null==deviceList){
            Set<String> keys = redisTemplate.keys(requestHead.get("systemCode")+"*");
            for(String key:keys){
                Map data=new HashMap();
                String[] arr=key.replace(requestHead.get("systemCode")+"","").split(":");
                if(arr[1].equals("runStatus")){
                    data.put("deviceCode",arr[0]);
                    data.put("runStatus",redisTemplate.opsForValue().get(key));
                    if(deviceMap.containsKey(arr[0])){
                        data.put("deviceName",deviceMap.get(arr[0]).getDeviceName());
                    }else{
                        data.put("deviceName","");
                    }
                    returnMap.add(data);
                }
            }
        }else{
            for(String devideCode:deviceList){
                Map data=new HashMap();
                data.put("deviceCode",devideCode);
                data.put("runStatus",redisTemplate.opsForValue().get(requestHead.get("systemCode")+devideCode+":runStatus"));
                if(deviceMap.containsKey(devideCode)){
                    data.put("deviceName",deviceMap.get(devideCode).getDeviceName());
                }else{
                    data.put("deviceName","");
                }
                returnMap.add(data);
            }
        }
        result.put("data",returnMap);
        return AjaxResult.success(result);
    }

    /**
     * 查询区域
     * @param params
     * @return
     */
    @PostMapping("/queryArea")
    public AjaxResult queryArea(@RequestBody JSONObject params){
        assert params !=null;
        //请求头
        JSONObject requestHead = params.getJSONObject("requestHead");
        assert requestHead != null;
        String systemCode = requestHead.getString("systemCode");
        List<TArea> tArea = areaRepository.findTArea(systemCode);
        log.info(JSON.toJSONString(tArea));
        AjaxResult.success(tArea);
        return AjaxResult.success(tArea);
    }

}
